﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using PSLib.CodeFormating.Lexems;
using LuaEditor2.UI.CodeEditor.IntellySense;

namespace LuaEditor2.UI.CodeEditor
{
	/// <summary>
	/// Interaction logic for IntellySensePopup.xaml
	/// </summary>
	public partial class IntellySensePopup : ListBox
	{
		#region Dependency properties

			#region Owner property

			public static readonly DependencyProperty OwnerProperty = DependencyProperty.Register(
													"Owner",
													typeof(RichTextBox),
													typeof(IntellySensePopup),
													new FrameworkPropertyMetadata(null, OwnerValueDependencyChanged));

			private static void OwnerValueDependencyChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
			{
				IntellySensePopup popup = target as IntellySensePopup;
				if (popup != null) popup.SetOwner(e.NewValue as RichTextBox, e.OldValue as RichTextBox);
			}

			private void SetOwner(RichTextBox newValue, RichTextBox oldValue)
			{
				if (newValue == oldValue) return;
				if (oldValue != null)
				{
					oldValue.TextChanged -= new TextChangedEventHandler(owner_TextChanged);
					oldValue.PreviewKeyDown -= new System.Windows.Input.KeyEventHandler(owner_PreviewKeyDown);
				}

				if (newValue != null)
				{
					newValue.TextChanged += new TextChangedEventHandler(owner_TextChanged);
					newValue.PreviewKeyDown += new System.Windows.Input.KeyEventHandler(owner_PreviewKeyDown);
				}
			}

			public RichTextBox Owner
			{
				get { return GetValue(IntellySensePopup.OwnerProperty) as RichTextBox; }
				set { SetValue(IntellySensePopup.OwnerProperty, value); }
			}

			#endregion

		#endregion

		#region Constructors

		public IntellySensePopup()
		{
			InitializeComponent();
			runPopupSupressed = null;
		}

		#endregion

		#region Event handlers

		private void owner_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
		{
			SyntaxItem sItem = GetSelectedSyntaxItem();
			Run run = GetActiveRun();

			//Check for popup ready status
			if (sItem == null || run == null || this.Visibility == Visibility.Hidden)
			{
				this.Visibility = System.Windows.Visibility.Hidden;
				return;
			}

			if (Keyboard.Modifiers == ModifierKeys.None)
			{
				e.Handled = true;
				switch (e.Key)
				{
					case Key.Up: this.SelectedIndex--; break;
					case Key.PageUp: if (this.SelectedIndex > 4) this.SelectedIndex -= 5; break;
					case Key.Down: this.SelectedIndex++; break;
					case Key.PageDown: this.SelectedIndex += 5; break;
					
					case Key.Escape: 
						this.Visibility = System.Windows.Visibility.Hidden;
						runPopupSupressed = GetActiveRun();
						e.Handled = false;
						break;
					case Key.Space:
					case Key.Enter: 
						AcceptSyntaxItem(run, sItem); 
						break;
					
					default: e.Handled = false; break;
				}

				if (e.Handled)
				{
					this.ScrollIntoView(this.SelectedItem);
				}
			}
		}

		private void owner_TextChanged(object sender, TextChangedEventArgs e)
		{
			if (this.Owner != null)
			{
				Rect rc = GetActiveRunRect();
				if (rc == Rect.Empty) return;
				Canvas.SetLeft(this, rc.Left);
				Canvas.SetTop(this, rc.Bottom);

				Run run = GetActiveRun();
				if (runPopupSupressed != null && runPopupSupressed != run) runPopupSupressed = null;

				if (run != null && runPopupSupressed == null && CheckPopupVisibility(run.Tag as Lexem))
				{
					this.SelectedIndex = 0;
					this.Visibility = System.Windows.Visibility.Visible;
				}
				else
				{
					this.Visibility = System.Windows.Visibility.Hidden;
				}
			}
		}

		private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
		{
			SyntaxItem sItem = e.Item as SyntaxItem;
			bool accepted = false;
			if (editedLexem != null && sItem != null)
			{
				accepted = accepted || sItem.Source.StartsWith(editedLexem.LexemSource, StringComparison.CurrentCultureIgnoreCase);
			}
			e.Accepted = accepted;
		}

		#endregion

		#region private methods

		private bool CheckPopupVisibility(Lexem lexem)
		{
			bool result = false;
			//Check for lexem
			if (lexem != null)
			{
				result = true;
				//Check for lexem type
				result = result && (lexem.Type == LexemType.Word || 
									lexem.Type == LexemType.Operator ||
									lexem.Type == LexemType.Constant);

				//Filter syntax source
				FilterSyntaxItems(lexem);

				//Check syntax collection items count
				result = result && (this.Items.Count != 0);
				result = result && !(this.Items.Count == 1 && (this.Items[0] as SyntaxItem).Source == lexem.LexemSource);
			}
			return result;
		}

		private void FilterSyntaxItems(Lexem lexem)
		{
			editedLexem = lexem;
			CollectionViewSource viewSource = (CollectionViewSource)FindResource("syntaxItemCollectionViewer");
			viewSource.View.Refresh();
			editedLexem = null;
		}

		private SyntaxItem GetSelectedSyntaxItem()
		{ 
			return this.SelectedItem as SyntaxItem;
		}

		private Run GetActiveRun()
		{
			Run result = null;
			if (this.Owner != null)
			{
				result = this.Owner.Selection.Start.Parent as Run;
			}
			return result;
		}

		private Rect GetActiveRunRect()
		{
			Rect result = Rect.Empty;
			if (this.Owner != null)
			{
				TextPointer pt = this.Owner.Selection.Start;
				if (pt != null)
				{
					while (pt.GetPointerContext(LogicalDirection.Backward) != TextPointerContext.ElementStart)
					{
						pt = pt.GetNextContextPosition(LogicalDirection.Backward);
						if (pt == null) return result;
					}
					result = pt.GetCharacterRect(LogicalDirection.Backward);
				}
			}
			return result;
		}

		private void AcceptSyntaxItem(Run run, SyntaxItem item)
		{
			run.Text = item.Source + " "; 
		}

		#endregion

		private Lexem editedLexem;
		private Run runPopupSupressed;
	}
}
